# 定义类
# python类的组成部分如下：】
#   类属性：直接定义在类中，方法外的【变量】
# 实例属性：定义在__init__方法中，使用self打点的【变量】
# 实例方法：定义在类中的函数，而且自带参数【self】
# 静态方法：使用装饰器【@staticmethod】修饰的方法
#   类方法：使用装饰器【@classmethod】修饰的方法
class Person:
    # 定义类属性
    # 类属性只能通过【类名.属性】访问
    subject = 'human'

    # 构造函数
    # 在__init__方法中初始化实例属性,实例属性不用直接定义，可以直接定义。
    # __init__是固定写法，不可以随便改，就好像java中的main方法的固定签名一样
    # 改变任何一个地方，java都不会当成是程序入口。
    # 其实也就是java中的构造函数，但是java可以理由多个构造函数，python就只有一个__init__构造函数
    def __init__(self, name, age):
        # 将参数赋值给当前实例属性
        self.name = name
        self.age = age

    # 实例方法：第一个参数固定式self，在self后面可以继续加参数
    def say(self, text):
        print('我是', self.name, '，我今年', self.age, '岁了，我想说：', text)

    # 静态方法:类似java中的静态方法
    # 和java一样，静态方法不能调用任何实例的东西（方法和属性）
    @staticmethod
    def print():
        print('我是人类！')

    # 类方法：使用装饰器【@classmethod】修饰的方法，第一个参数必须是cls，cls表示类本身
    # 实例对象和类对象都可以调用
    # ！！！类方法作用：类方法用在模拟java定义多个构造函数的情况，因为python的构造函数就有一个__init__初始化方法。
    @classmethod
    def print1(cls):
        # 输出：<class '__main__.Person'>
        print(cls)
        # <class 'type'>
        print(type(cls))
        # 输出：human
        print(cls.subject)
        # 一下代码报错，类属性只能通过【类名.属性】
        # 在类方法中访问类属性则是通过【cls.属性这种方式】
        # print(subject)

    # 使用类方法创建实例对象
    @classmethod
    def create_install(cls, name, age):
        # 类方法内部调用方法：cls()相当于直接实例化了一个对象。cls()方法最后会调用到__init__方法中去
        return cls(name, age)


# 创建类实例
# 对象名=类名()
person = Person('yinsc', 18)
# 调用实例方法
# 实例方法的第一个参数self不用自己传递。
person.say('hhhh')

# 调用静态方法
Person.print()
# 实例对象调用静态方法
person.print()

print('-' * 40)

# 调用类方法
Person.print1()
# 实例调用类方法
person.print1()

# person = Person(subject=123)


p = Person.create_install("yinsc",16)
# 输出 create_install:yinsc, 16
print(f"create_install:{p.name}, {p.age}")